﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Net.Mail;
using System.Threading;
using System.Net.Security;

namespace Pop3Client
{
    public delegate void Pop3InfoHandler(string message);
    public delegate void Pop3MailReceivedHandler(MailMessage mail);
    public class Pop3Client
    {
        TcpClient client;
        Stream stream;
        StreamReader reader;
        bool useSsl = false;

        public event Pop3InfoHandler Info;
        public event Pop3MailReceivedHandler MailReceived;

        private string Read()
        {
            return reader.ReadLine();
        }

        private void Write(string message)
        {
            byte[] data = Encoding.Default.GetBytes(message);
            stream.Write(data, 0, data.Length);
        }

        public void Connect(string server, string username, string password)
        {
            Connect(server, username, password, false);
        }

        public void Connect(string server, string username, string password, bool useSsl)
        {
            try
            {
                OnInfo("Verbinde mit Server...");
                client = new TcpClient(server, useSsl ? 995 : 110);
                if (useSsl)
                {
                    SslStream sslStream = new SslStream(client.GetStream(), false);
                    sslStream.AuthenticateAsClient(server);
                    stream = sslStream;
                    reader = new StreamReader(sslStream);
                }
                else
                {
                    stream = client.GetStream();
                    reader = new StreamReader(client.GetStream());
                }

                string message;
                string response;

                response = Read();
                if (response.Substring(0, 3) != "+OK")
                {
                    throw new Pop3Exception(response);
                }
                OnInfo("Authentifiziere...");

                message = "USER " + username + "\r\n";
                Write(message);
                response = Read();
                if (response.Substring(0, 3) != "+OK")
                {
                    throw new Pop3Exception(response);
                }

                message = "PASS " + password + "\r\n";
                Write(message);
                response = Read();
                if (response.Substring(0, 3) != "+OK")
                {
                    throw new Pop3Exception(response);
                }
                OnInfo("Verbindung hergestellt");
            }
            catch (Exception ex)
            {
                OnInfo("Fehler beim Verbindungsaufbau");
                throw ex;
            }
        }

        public List<MailMessage> getMails()
        {
            return getMails(false);
        }

        public void getMailsAsync()
        {
            new Thread(new ThreadStart(getMailsThread)).Start();
        }

        private void getMailsThread()
        {
            getMails(true);
        }

        private List<MailMessage> getMails(bool async)
        {
            OnInfo("Empfange Mails...");
            List<MailMessage> mails = new List<MailMessage>();
            List<Pop3Message> list = List();
            foreach (Pop3Message message in list)
            {
                OnInfo("Empfange Mail " + message.Id + " von " + list.Count);
                MailMessage mail = new MailMessage();
                mail.Body = Receive(message);
                if (!String.IsNullOrWhiteSpace(mail.Body))
                    mail.Body = mail.Body.Substring(mail.Body.IndexOf("<?xml"));
                mails.Add(mail);
                //if (async)
                //{
                OnMailReceived(mail);
                //}
            }
            OnInfo("Empfang abgeschlossen");
            return mails;
        }

        public List<Pop3Message> List()
        {
            string message;
            string response;

            List<Pop3Message> retval = new List<Pop3Message>();
            message = "LIST\r\n";
            Write(message);
            response = Read();
            if (response.Substring(0, 3) != "+OK")
            {
                throw new Pop3Exception(response);
            }

            while (true)
            {
                response = Read();
                if (response == ".")
                {
                    return retval;
                }
                else
                {
                    Pop3Message msg = new Pop3Message();
                    char[] seps = { ' ' };
                    string[] values = response.Split(seps);
                    msg.Id = int.Parse(values[0]);
                    retval.Add(msg);
                    continue;
                }
            }
        }

        public string Receive(Pop3Message message)
        {
            return Receive(message.Id);
        }

        public string Receive(int messageId)
        {
            string message;
            string response;
            string mail = "";

            message = "RETR " + messageId + "\r\n";
            Write(message);
            response = Read();
            if (response.Substring(0, 3) != "+OK")
            {
                throw new Pop3Exception(response);
            }
            while (true)
            {
                response = Read();
                if (response == ".")
                {
                    break;
                }
                else
                {
                    mail += response.TrimStart();
                }
            }
            return mail.Replace("!\r\n", "").Replace("\r\n", "").Replace("!\n", "").Replace("\n", "");
        }

        public void Disconnect()
        {
            OnInfo("Schließe Verbindung...");
            string message;
            string response;
            message = "QUIT\r\n";
            Write(message);
            response = Read();
            if (response.Substring(0, 3) != "+OK")
            {
                throw new Pop3Exception(response);
            }
            OnInfo("Verbindung geschlossen");
        }

        private void OnInfo(string message)
        {
            if (Info != null)
                Info(message);
        }

        private void OnMailReceived(MailMessage mail)
        {
            if (MailReceived != null)
                MailReceived(mail);
        }
    }
}